import { Injectable, Injector } from '@angular/core';
import { Router } from '@angular/router';
import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpResponseBase,
  HttpErrorResponse,
} from '@angular/common/http';
import { Observable, of, throwError } from 'rxjs';
import { catchError, mergeMap } from 'rxjs/operators';

import { NzNotificationService } from 'ng-zorro-antd/notification';

import { AuthService } from '@/core/auth/auth.service';
import { environment } from '@env/environment';

const CODEMESSAGE: { [key: number]: string } = {
  200: '服务器成功返回请求的数据。',
  201: '新建或修改数据成功。',
  202: '一个请求已经进入后台排队（异步任务）。',
  204: '删除数据成功。',
  400: '发出的请求有错误，服务器没有进行新建或修改数据的操作。',
  401: '用户没有权限（令牌、用户名、密码错误）。',
  403: '用户得到授权，但是访问是被禁止的。',
  404: '发出的请求针对的是不存在的记录，服务器没有进行操作。',
  406: '请求的格式不可得。',
  410: '请求的资源被永久删除，且不会再得到的。',
  422: '当创建一个对象时，发生一个验证错误。',
  500: '服务器发生错误，请检查服务器。',
  502: '网关错误。',
  503: '服务不可用，服务器暂时过载或维护。',
  504: '网关超时。',
};

@Injectable()
export class DefaultInterceptor implements HttpInterceptor {
  constructor(private injector: Injector) {}

  private get notification(): NzNotificationService {
    return this.injector.get(NzNotificationService);
  }

  private goTo(url: string): void {
    setTimeout(() => this.injector.get(Router).navigateByUrl(url));
  }

  private toLogin(): void {
    this.notification.error('未登录或登录已过期，请重新登录', '');
    this.goTo('/login');
  }

  private get authToken(): string {
    return this.injector.get(AuthService).getToken();
  }

  private handleResponseError(err: HttpErrorResponse): Observable<any> {
    switch (err.status) {
      case 400:
        break;
      case 401:
        this.toLogin();
        break;
      case 500:
        this.notification.error('服务器错误', '请稍候再试');
    }
    if (err instanceof HttpErrorResponse) {
      return throwError(err);
    }
    return of(err);
  }

  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    let url = req.url;

    if (!url.startsWith('https://') && !url.startsWith('http://')) {
      url = environment.api.baseUrl + url;
    }

    const newReq = req.clone({
      url,
      setHeaders: { Authorization: this.authToken },
    });

    return next
      .handle(newReq)
      .pipe(
        catchError((err: HttpErrorResponse) => this.handleResponseError(err))
      );
  }
}
